package detector

import (
    "google.golang.org/grpc"
    "../pb"
    "../common"
    "context"
    "time"
)

type Detection struct {
    conn     *grpc.ClientConn
    node     common.Node
    stopping chan interface{}
    stopped  chan interface{}
}

func (ct *Detection) Stop() {
    close(ct.stopping)
    <-ct.stopped
}

var startTime = common.NowMillisecond()

func (ct *Detection) sendBeaconForAck(fromNode common.Node) BeaconAckWithError {
    var ack *pb.BeaconAck
    var err error
    if ct.conn == nil {
        if ct.conn, err = grpc.Dial(string(ct.node), dialOpt); err != nil {
            return BeaconAckWithError{err: err}
        }
    }
    cli := pb.NewFailureDetectorClient(ct.conn)
    ctx := context.Background()
    beacon := &pb.BeaconMsg{
        Time:      common.NowMillisecond(),
        FromNode:  string(fromNode),
        ToNode:    string(ct.node),
        StartTime: startTime,
    }
    ack, err = cli.Ping(ctx, beacon)
    //handle redail error,let conn=nil
    return BeaconAckWithError{ack: ack, err: err}
}

func NewClientTask(beaconIntervalMilliseconds, delayMilliseconds uint64,
    toNode, fromNode common.Node, ackChan chan BeaconAckWithError) *Detection {
    ct := &Detection{}
    ct.node = common.Node(toNode)
    ct.stopping = make(chan interface{})
    ct.stopped = make(chan interface{})
    tk := time.Tick(time.Duration(beaconIntervalMilliseconds) * time.Millisecond)
    go func() {
        <-time.After(time.Duration(delayMilliseconds) * time.Millisecond)
    LOOP:
        for {
            select {
            case <-tk:
                ackChan <- ct.sendBeaconForAck(fromNode)
            case <-ct.stopping:
                if ct.conn != nil {
                    ct.conn.Close()
                }
                break LOOP
            }
        }
        close(ct.stopped)
    }()
    return ct
}
